package com.example.shiro.config;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.shiro.entity.Permission;
import com.example.shiro.entity.Role;
import com.example.shiro.entity.SysUser;
import com.example.shiro.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.concurrent.TimeUnit;

@Slf4j
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SysUserService sysUserService;

    private int TIMEOUT = 30;
    /**
     * 用户认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 加这一步的目的是在Post请求的时候会先进认证，然后在到请求
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        // 获取用户信息
        //String name = authenticationToken.getPrincipal().toString();
        String username = String.valueOf(token.getPassword());
        String password = String.valueOf(token.getUsername());
        SysUser user = new SysUser();
        try{
            String result = redisTemplate.opsForValue().get(username);
            if(result != null){
                JSONObject jsonObject = JSON.parseObject(result);
                BeanUtil.copyProperties(jsonObject,user);
                log.info("user-:{}",user);
            } else {
                user = sysUserService.authoriz(username);
                log.info("user--:{}",user);
                redisTemplate.opsForValue().set(username,JSON.toJSONString(user),TIMEOUT, TimeUnit.SECONDS);
            }
        }catch (Exception e){
            log.error("{}",e);
        }
        if(user.getStatus()==1){
            throw new LockedAccountException("该用户已锁定");
        }
        if (user == null) {
            // 这里返回后会报出对应异常
            return null;
        } else {
            // 这里验证authenticationToken和simpleAuthenticationInfo的信息
            String credit = new Sha256Hash(password, user.getSalt(), 1000).toBase64();
            token.setPassword(credit.toCharArray());
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,
                    user.getPassword(), getName());
            return simpleAuthenticationInfo;
        }
    }

    /**
     * 角色权限和对应权限添加
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取登录用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        // 查询用户名称
        SysUser user = new SysUser();
        try{
            String result = redisTemplate.opsForValue().get(username);
            if(result != null){
                JSONObject jsonObject = JSON.parseObject(result);
                BeanUtil.copyProperties(jsonObject,user);
                log.info("user=:{}",user);
            } else {
                user = sysUserService.authoriz(username);
                log.info("user==:{}",user);
                redisTemplate.opsForValue().set(username,JSON.toJSONString(user),TIMEOUT,TimeUnit.SECONDS);
            }
        }catch (Exception e){
            log.error("{}",e);
        }
        // 添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for (Role role : user.getRoles()) {
            // 添加角色
            simpleAuthorizationInfo.addRole(role.getName());
            for (Permission permission : role.getPermissions()) {
                // 添加权限
                simpleAuthorizationInfo.addStringPermission(permission.getName());
            }
        }
        return simpleAuthorizationInfo;
    }
}
